from khronos import *
from khronos.extras.components import *

class CustomerGenerator(Composite):
    @chain
    def initializer(self):
        self.clear()
        rng = self.get_rng()
        rsc = self.get_config()
        n = 0
        while True:
            yield rng.expovariate(40.0) * HOUR
            self.launch(Thread(target=self.use(rsc), name=str(n), parent=self))
            n += 1
            
    @chain
    def use(self, resource):
        yield resource.acquire()
        yield max(0.5, self.get_rng().gauss(5.0, 2.0)) * MINUTE
        resource.release()
        
def model():
    r = Resource(4, name="resource")
    c = TSeriesCollector(getter=r.queue_size, period=MINUTE, name="collector")
    g = CustomerGenerator(name="customers", config=r)
    return Composite(name="root", children=[r, c, g])
    
def main():
    m = model()
    k = Khronos(m)
    k.run_experiment(myexp(runs=1), trace=False)
    
m = model()
k = Khronos(m)

"""Below we create an experiment definition. The experiment consists by default of 10 simulations
with a duration of one day each. The only indicator taken is the weighted mean queue size at the
end of the simulation. The indicator getter is defined after the experiment class, using the 
getter() function decorator of class Indicator."""
class myexp(Experiment):
    runs = 10
    duration = DAY
    indicators = Namespace(qsize=StatIndicator.subclass("QueueSizeIndicator"))
    
    def at_run_start(self):
        print "Run", self.run, "ongoing...", 
        
    def at_run_end(self):
        print "finished."
        
    def at_end(self):
        qsize = self.indicators.qsize.stat
        qsize.run_chart(title="collection example", 
                        xlabel="Runs", 
                        ylabel="Avg queue size", 
                        show_stddev=False)
                        
@myexp.indicators.qsize.getter
def queuesize(indicator):
    model = indicator.experiment.model
    return model.find("collector").stat().wmean()
    
